﻿#include "stdafx.h"
#include <QDateTime>

#include "TaskTreeModel.h"
#include "ProjectPlan/PPContext.h"
#include "ProjectPlan/PPCalendar.h"
#include "ProjectPlan/PPPreTask.h"

namespace LBPROJLOGIC
{
    CTaskTreeModel::CTaskTreeModel(QObject *parent)
        : QAbstractItemModel(parent)
    {
    }

    CTaskTreeModel::~CTaskTreeModel()
    {
    }

    void CTaskTreeModel::SetTaskGroup(CRefPtr<LBPROJ::ITaskGroup> pGroup)
    {
        m_pGroup = pGroup;
    }

    QVariant CTaskTreeModel::data(const QModelIndex & index, int role) const
    {
        if (role == Qt::DisplayRole || role == Qt::EditRole)
        {
            LBPROJ::ITask* pTask = getItem(index);
            if (pTask != nullptr)
            {
                int taskSequence = pTask->GetSequenceNumber();
                auto iter = m_indexMap.find(taskSequence);
                if(iter == m_indexMap.end() || (iter != m_indexMap.end() && !(*iter).second.isValid()))
                    m_indexMap[taskSequence] = index;

                switch (index.column())
                {
                case TC_NAME:
                    return QString::fromStdWString(pTask->GetName());
                case TC_SPAN:
                    if (role == Qt::DisplayRole)
                    {
                        if (pTask->IsMileStone())
                            return u8"0 天";
                        else
                            return QString::fromStdWString(pTask->GetSpan()->GetDaysAsString());
                    }
                    else
                    {
                        if (pTask->IsMileStone())
                            return 0;
                        else
                            return QString::fromStdWString(pTask->GetSpan()->GetDaysAsString(false));
                    }
                case TC_START:
                    return QDateTime::fromTime_t(pTask->GetStart()).toString("yyyy-MM-dd");
                case TC_END:
                    if (pTask->IsMileStone())
                        return u8"-";
                    else
                        return QDateTime::fromTime_t(pTask->GetFinish()).toString("yyyy-MM-dd");
                case TC_ACTRUAL_SPAN:
                    if (role == Qt::DisplayRole)
                    {
                        if (pTask->IsMileStone())
                            return u8"0 天";
                        else
                            return QString::fromStdWString(pTask->GetActualSpan()->GetDaysAsString());
                    }
                    else
                    {
                        if (pTask->IsMileStone())
                            return 0;
                        else
                            return QString::fromStdWString(pTask->GetActualSpan()->GetDaysAsString(false));
                    }
                case TC_ACTRUAL_START:
                    return QDateTime::fromTime_t(pTask->GetActualStart()).toString("yyyy-MM-dd");
                case TC_ACTRUAL_END:
                    if (pTask->IsMileStone())
                        return u8"-";
                    else
                        return QDateTime::fromTime_t(pTask->GetActualFinish()).toString("yyyy-MM-dd");
                case TC_INDEX:
                    return taskSequence;
                case TC_PRE_TASK:
                    return QString::fromStdWString(pTask->GetPreTaskGroup()->GetPreTaskGroupAsString());
                case TC_MILESTONE:
                {
                    if (role == Qt::DisplayRole)
                        return (pTask->IsMileStone() ? u8"√" : QString());
                    else
                        return pTask->IsMileStone();
                }
                default:
                    return QVariant();
                }
            }
        }
        return QVariant();
    }

    QVariant CTaskTreeModel::headerData(int section, Qt::Orientation orientation, int role) const
    {
        if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
        {
            switch (section)
            {
            case TC_NAME:
                return u8"任务名称";
            case TC_INDEX:
                return u8"序号";
            case TC_SPAN:
                return u8"计划工期";
            case TC_START:
                return u8"计划开始";
            case TC_END:
                return u8"计划结束";
            case TC_ACTRUAL_SPAN:
                return u8"实际工期";
            case TC_ACTRUAL_START:
                return u8"实际开始";
            case TC_ACTRUAL_END:
                return u8"实际结束";
            case TC_MILESTONE:
                return u8"里程碑";
            case TC_PRE_TASK:
                return u8"前置任务";
            default:
                return QVariant();
            }
        }

        //if (orientation == Qt::Vertical && role == Qt::DisplayRole)
        //{
        //    return section;
        //}
        return QVariant();
    }

    bool CTaskTreeModel::setData(const QModelIndex & index, const QVariant & value, int role)
    {
        //return false;
        if (role != Qt::EditRole)
            return false;

        LBPROJ::ITask* pTask = getItem(index);
        if (pTask == nullptr)
            return false;

        switch (index.column())
        {
        case TC_NAME:
            pTask->SetName(value.toString().toStdWString());
            break;
        case TC_SPAN:
        {
            if (value.toInt() <= 0)
            {
                pTask->SetAsMilestone(true);
            }
            else
            {
                pTask->SetAsMilestone(false);
                CRefPtr<LBPROJ::ITimeSpan> pSpan = LBPROJ::CreateTimeSpan(LBPROJ::ITimeSpan::E_Day, value.toInt() - 1);
                time_t finish = m_pGroup->GetContext()->GetCalendar()->GetEndTime(pTask->GetStart(), pSpan);
                pTask->SetFinish(finish);
            }
        }
        break;
        case TC_START:
        {
            CRefPtr<LBPROJ::ITimeSpan> pSpan = pTask->GetSpan();
            pTask->SetStart(value.toDateTime().toTime_t());
            time_t finish = m_pGroup->GetContext()->GetCalendar()->GetEndTime(pTask->GetStart(), pSpan);
            pTask->SetFinish(finish);
        }
        break;
        case TC_END:
        {
            time_t tFinish = value.toDateTime().toTime_t();
            if(tFinish >= pTask->GetStart())
                pTask->SetFinish(tFinish);
        }
        break;
        case TC_ACTRUAL_SPAN:
        {
            if (value.toInt() <= 0)
            {
                pTask->SetAsMilestone(true);
            }
            else
            {
                pTask->SetAsMilestone(false);
                CRefPtr<LBPROJ::ITimeSpan> pSpan = LBPROJ::CreateTimeSpan(LBPROJ::ITimeSpan::E_Day, value.toInt() - 1);
                time_t finish = m_pGroup->GetContext()->GetCalendar()->GetEndTime(pTask->GetActualStart(), pSpan);
                pTask->SetActualFinish(finish);
            }
        }
        break;
        case TC_ACTRUAL_START:
        {
            CRefPtr<LBPROJ::ITimeSpan> pSpan = pTask->GetActualSpan();
            pTask->SetActualStart(value.toDateTime().toTime_t());
            time_t finish = m_pGroup->GetContext()->GetCalendar()->GetEndTime(pTask->GetActualStart(), pSpan);
            pTask->SetActualFinish(finish);
        }
        break;
        case TC_ACTRUAL_END:
        {
            time_t tFinish = value.toDateTime().toTime_t();
            if (tFinish >= pTask->GetActualStart())
                pTask->SetActualFinish(value.toDateTime().toTime_t());
        }
        break;
        case TC_MILESTONE:
            pTask->SetAsMilestone(value.toBool());
            break;
        case TC_PRE_TASK:
            pTask->GetPreTaskGroup()->PreTaskGroupFromString(value.toString().toStdWString());
            break;
        default:
            return false;
        }

        emit dataChanged(index, index);
        return true;
    }

    QModelIndex CTaskTreeModel::index(int row, int column, const QModelIndex & parent) const
    {
        if (!parent.isValid())
        {
            auto iter = m_pGroup->CreateIterator();
            if (row >= 0 && row < iter->GetCount())
                return createIndex(row, column, iter->GetChild(row));
        }
        else
        {
            LBPROJ::ITask* pTask = getItem(parent);
            if (pTask != nullptr)
            {
                auto iter = pTask->CreateIterator();
                if (row >= 0 && row < iter->GetCount())
                {
                    return createIndex(row, column, iter->GetChild(row));
                }
            }
        }

        return QModelIndex();
    }

    QModelIndex CTaskTreeModel::parent(const QModelIndex & index) const
    {
        LBPROJ::ITask* pTask = getItem(index);
        if (pTask != nullptr)
        {
            LBPROJ::ITask* pParent = pTask->GetParent();
            if (pParent != nullptr)
            {
                auto iter = pParent->CreateIterator();
                return createIndex(iter->IndexOf(pTask), 0, pParent);
            }
        }
        return QModelIndex();
    }

    int CTaskTreeModel::rowCount(const QModelIndex & parent) const
    {
        LBPROJ::ITask* pTask = getItem(parent);
        if (pTask == nullptr)
        {
            // 根节点下的数据行数
            auto iter = m_pGroup->CreateIterator();
            return iter->GetCount();
        }
        else
        {
            // 节点下的数据行数
            auto iter = pTask->CreateIterator();
            return iter->GetCount();
        }
    }

    int CTaskTreeModel::columnCount(const QModelIndex & parent) const
    {
        return TC_COLUMN_MAX;
    }

    bool CTaskTreeModel::removeRows(int position, int rows, const QModelIndex & parent)
    {
        beginRemoveRows(parent, position, position);		//暂时只支持一次删除一行
        LBPROJ::ITask* pParent = getItem(parent);
        if (pParent != nullptr)
        {
            auto iter = pParent->CreateIterator();
            LBPROJ::ITask* pTask = iter->GetChild(position);
            pParent->DelItem(pTask);
        }
        else
        {
            auto iter = m_pGroup->CreateIterator();
            LBPROJ::ITask* pTask = iter->GetChild(position);
            m_pGroup->DelItem(pTask);
        }
        endRemoveRows();
        ResetIndexMap();
        return true;
    }

    bool CTaskTreeModel::insertRows(int position, int rows, const QModelIndex & parent)
    {
        beginInsertRows(parent, position, position);		//暂时只支持一次插入一行
        LBPROJ::ITask* pParent = getItem(parent);
        LBPROJ::ITask* pTask;
        CRefPtr<LBPROJ::ITask> pNewTask = LBPROJ::CreateTask(L"[no data]");
        QDateTime curDate;
        curDate.setDate(QDate::currentDate());
        pNewTask->SetStart(curDate.toTime_t());
        pNewTask->SetFinish(curDate.toTime_t());
        pNewTask->SetActualStart(pNewTask->GetStart());
        pNewTask->SetActualFinish(pNewTask->GetFinish());

        if (pParent != nullptr)
        {
            auto iter = pParent->CreateIterator();
            pTask = iter->GetChild(position);
            pParent->AddItem(pNewTask, pTask);
        }
        else
        {
            auto iter = m_pGroup->CreateIterator();
            pTask = iter->GetChild(position);
            m_pGroup->AddItem(pNewTask, pTask);
        }
        endInsertRows();
        ResetIndexMap();

        return true;
    }

    Qt::ItemFlags CTaskTreeModel::flags(const QModelIndex & index) const
    {
        if (!index.isValid())
            return Qt::ItemIsEnabled;

        auto flag = QAbstractItemModel::flags(index);
        LBPROJ::ITask* pTask = getItem(index);
        if (pTask != nullptr && pTask->IsParentTask())			//如果当前选中的任务有子任务，则只允许编辑名称和前置任务
        {
            if (index.column() != TC_NAME && index.column() != TC_PRE_TASK)
                return flag;
        }

        if (pTask != nullptr && pTask->IsMileStone())			//如果当前选中的任务为里程碑，则只不允许编辑结束时间
        {
            if (index.column() == TC_END || index.column() == TC_ACTRUAL_END)
                return flag;

        }
        flag = flag | Qt::ItemIsEditable;
        return flag;
    }

    bool CTaskTreeModel::GetTaskInfo(int sequence, LBPROJGUI::STaskInfo& taskInfo) const
    {
        LBPROJ::ITask* pTask = m_pGroup->FindTaskBySequence(sequence);
        if (pTask != nullptr)
        {
            taskInfo.name = pTask->GetName();
            taskInfo.start = QDateTime::fromTime_t(pTask->GetStart()).date();
            taskInfo.finish = QDateTime::fromTime_t(pTask->GetFinish()).date();
            taskInfo.actualStart = QDateTime::fromTime_t(pTask->GetActualStart()).date();
            taskInfo.actualFinish = QDateTime::fromTime_t(pTask->GetActualFinish()).date();
            taskInfo.milestone = pTask->IsMileStone();
            taskInfo.isParent = pTask->IsParentTask();

            LBPROJGUI::SPreTaskInfo preTaskInfo;
            taskInfo.preTask.clear();
            auto iter = pTask->GetPreTaskGroup()->CreateIterator();
            for (iter->First(); !iter->IsDone(); iter->Next())
            {
                preTaskInfo.start = QDateTime::fromTime_t(iter->GetCurrentItem()->GetStart()).date();
                preTaskInfo.finish = QDateTime::fromTime_t(iter->GetCurrentItem()->GetFinish()).date();
                preTaskInfo.preTaskSequence = iter->GetCurrentItem()->GetPreTask()->GetSequenceNumber();
                preTaskInfo.startOnLeft = (iter->GetCurrentItem()->GetType() == LBPROJ::IPreTask::SS || iter->GetCurrentItem()->GetType() == LBPROJ::IPreTask::SF);
                preTaskInfo.endOnLeft = (iter->GetCurrentItem()->GetType() == LBPROJ::IPreTask::SS || iter->GetCurrentItem()->GetType() == LBPROJ::IPreTask::FS);
                taskInfo.preTask.push_back(preTaskInfo);
            }
        }
        return (pTask != nullptr);
    }

    bool CTaskTreeModel::IsTaskShown(int sequence, const QTreeView * treeView) const
    {
        const QModelIndex& index = m_indexMap[sequence];
        LBPROJ::ITask* pTask = m_pGroup->FindTaskBySequence(sequence);

        //依次检测节点的父节点，如果检测到一个父节点是收起状态，则任务将不被显示
        LBPROJ::ITask* pParent = pTask->GetParent();
        while (pParent != nullptr)
        {
            QModelIndex parentIndex = m_indexMap[pParent->GetSequenceNumber()];
            if (!treeView->isExpanded(parentIndex))
                return false;
            pParent = pParent->GetParent();
        }
        return true;
    }

    void CTaskTreeModel::GetTaskGroupInfo(LBPROJGUI::STaskGroupInfo & taskGroupInfo) const
    {
        taskGroupInfo.start = QDateTime::fromTime_t(m_pGroup->GetStart()).date();
        taskGroupInfo.finish = QDateTime::fromTime_t(m_pGroup->GetFinish()).date();
        taskGroupInfo.actualStart = QDateTime::fromTime_t(m_pGroup->GetActualStart()).date();
        taskGroupInfo.actualFinish = QDateTime::fromTime_t(m_pGroup->GetActualFinish()).date();
    }

    int CTaskTreeModel::GetSelectedItemSecquence(const QTreeView * treeView) const
    {
        QModelIndex curIndex = treeView->currentIndex();
        LBPROJ::ITask* pTask = getItem(curIndex);
        int rtn = -1;
        if (pTask != nullptr)
            rtn = pTask->GetSequenceNumber();
        return rtn;
    }

    void CTaskTreeModel::ResetIndexMap()
    {
        m_indexMap.clear();
    }

    void CTaskTreeModel::ResetModel()
    {
        ResetIndexMap();
        beginResetModel();
        endResetModel();
    }

    LBPROJ::ITask * CTaskTreeModel::getItem(const QModelIndex & index) const
    {
        if (index.isValid())
        {
            LBPROJ::ITask* pTask = static_cast<LBPROJ::ITask*>(index.internalPointer());
            if (pTask != nullptr)
                return pTask;
        }
        return nullptr;
    }
}
